package aceim.protocol.snuk182.xmppcrypto; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.RosterGroup; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence.Mode; import org.jivesoftware.smack.packet.Presence.Type; import org.jivesoftware.smack.packet.RosterPacket; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.MessageEventManager; import org.jivesoftware.smackx.packet.EncryptedMessage; import org.jivesoftware.smackx.packet.SignedPresence; import org.jivesoftware.smackx.provider.EncryptedDataProvider; import aceim.api.dataentity.Buddy; import aceim.api.dataentity.BuddyGroup; import aceim.api.dataentity.OnlineInfo; import aceim.api.dataentity.TextMessage; import aceim.api.service.ApiConstants; import aceim.api.utils.Logger; import aceim.protocol.snuk182.xmpp.common.XMPPApiConstants; import aceim.protocol.snuk182.xmpp.common.XMPPEntityAdapter; import aceim.protocol.snuk182.xmpp.common.XMPPServiceInternal; import aceim.protocol.snuk182.xmppcrypto.utils.ResourceUtils; import android.content.Context; import android.text.TextUtils; public class XMPPCryptoEntityAdapter extends XMPPEntityAdapter { static final byte INVISIBLE_STATUS_ID = 5; private static final Mode[] presenceModes = {Mode.available, Mode.away, Mode.xa, Mode.dnd, Mode.chat}; private EncryptedDataProvider edProvider = null; @Override public TextMessage xmppMessage2TextMessage(Message message, XMPPServiceInternal service, boolean resourceAsWriterId){ if (message == null){ return null; } TextMessage txtMessage; if (resourceAsWriterId){ txtMessage = new TextMessage(service.getOnlineInfo().getServiceId(), StringUtils.parseBareAddress(message.getFrom())); txtMessage.setContactDetail(StringUtils.parseResource(message.getFrom())); } else { String from = normalizeJID(message.getFrom()); txtMessage = new TextMessage(service.getOnlineInfo().getServiceId(), from); } txtMessage.setMessageId(message.getPacketID() != null ? message.getPacketID().hashCode() : message.hashCode()); txtMessage.setTime(System.currentTimeMillis()); txtMessage.setText(message.getBody()); txtMessage.setIncoming(true); if (edProvider != null){ PacketExtension ext = message.getExtension("x", "jabber:x:encrypted"); if (ext != null){ EncryptedMessage ems = (EncryptedMessage) ext; try { txtMessage.setText(ems.decryptAndGet(edProvider.getMyKey(), edProvider.getMyKeyPw())); } catch (Exception e) { Logger.log(e); } if (edProvider.getKeyStorage().get(txtMessage.getContactUid()) != null){ OnlineInfo info = service.getRosterListener().getPresenceCache().get(txtMessage.getContactUid()); if (info != null && !info.getFeatures().containsKey(XMPPCryptoApiConstants.FEATURE_ENCRYPTION_ON)) { info.getFeatures().putBoolean(XMPPCryptoApiConstants.FEATURE_ENCRYPTION_ON, true); info.getFeatures().remove(XMPPCryptoApiConstants.FEATURE_ENCRYPTION_OFF); service.getService().getCoreService().buddyStateChanged(Arrays.asList(info)); } } } } return txtMessage; } @Override public Presence userStatus2XMPPPresence(Byte status) { Presence presence; if (status < 0 || status >= presenceModes.length) { presence = new Presence(Type.unavailable); } else { presence = new Presence(Type.available); presence.setMode(presenceModes[status]); } if (edProvider != null){ SignedPresence spr = new SignedPresence(); try { spr.signAndSet(presence.getStatus(), edProvider.getMyKey(), edProvider.getMyKeyPw()); presence.addExtension(spr); } catch (XMPPException e) { Logger.log(e); } } return presence; } @Override public OnlineInfo presence2OnlineInfo(Presence presence, Context context, byte serviceId, String ownerJid, OnlineInfo onlineInfo){ if (presence == null){ return null; } String jid = normalizeJID(presence.getFrom()); OnlineInfo info; if (onlineInfo != null && jid.equals(onlineInfo.getProtocolUid())) { info = onlineInfo; } else { info = new OnlineInfo(serviceId, jid); } String resource = StringUtils.parseResource(presence.getFrom()); if (!TextUtils.isEmpty(resource)) { info.getFeatures().putString(ApiConstants.FEATURE_BUDDY_RESOURCE, resource); } info.getFeatures().putByte(ApiConstants.FEATURE_STATUS, xmppPresence2UserStatus(presence)); info.setXstatusName(presence.getStatus()); info.getFeatures().putBoolean(ApiConstants.FEATURE_FILE_TRANSFER, true); if (edProvider != null){ String buddyPGPKey = context.getSharedPreferences(ownerJid, 0).getString(ResourceUtils.BUDDY_PUBLIC_KEY_PREFIX + info.getProtocolUid(), null); if (buddyPGPKey != null) { info.getFeatures().putBoolean(XMPPCryptoApiConstants.FEATURE_ENCRYPTION_OFF, true); info.getFeatures().putBoolean(XMPPCryptoApiConstants.FEATURE_REMOVE_PUBLIC_KEY, true); PacketExtension ext = presence.getExtension("x", "jabber:x:signed"); if (ext != null){ SignedPresence spr = (SignedPresence) ext; try { info.setXstatusName(spr.verifyAndGet(buddyPGPKey)); } catch (Exception e) { Logger.log(e); } } } else { info.getFeatures().putBoolean(XMPPCryptoApiConstants.FEATURE_ADD_PUBLIC_KEY, true); } } return info; } @Override public Buddy rosterEntry2Buddy(RosterEntry entry, String ownerJid, Context context, byte serviceId){ if (entry == null){ return null; } Buddy buddy = new Buddy(normalizeJID(entry.getUser()), ownerJid, XMPPApiConstants.PROTOCOL_NAME, serviceId); buddy.setName(entry.getName()); buddy.setId(entry.getUser().hashCode()); buddy.setGroupId((entry.getGroups() != null && entry.getGroups().size() > 0) ? entry.getGroups().iterator().next().getName() : ApiConstants.NO_GROUP_ID); //buddy.clientId = getClientId(entry.getUser()); if (entry.getStatus()!=null && entry.getStatus().equals(RosterPacket.ItemStatus.SUBSCRIPTION_PENDING)){ //buddy.visibility = Buddy.VIS_NOT_AUTHORIZED; } OnlineInfo info = buddy.getOnlineInfo(); if (edProvider != null){ String buddyPGPKey = context.getSharedPreferences(ownerJid, 0).getString(ResourceUtils.BUDDY_PUBLIC_KEY_PREFIX + info.getProtocolUid(), null); if (buddyPGPKey != null) { //info.getFeatures().putBoolean(XMPPApiConstants.FEATURE_ENCRYPTION_OFF, true); info.getFeatures().putBoolean(XMPPApiConstants.FEATURE_REMOVE_PUBLIC_KEY, true); edProvider.getKeyStorage().put(info.getProtocolUid(), null); } else { info.getFeatures().putBoolean(XMPPApiConstants.FEATURE_ADD_PUBLIC_KEY, true); } } return buddy; } @Override public BuddyGroup rosterGroup2BuddyGroup(RosterGroup entry, Collection<RosterEntry> buddies, String ownerUid, Context context, byte serviceId){ if (entry == null){ return null; } BuddyGroup group = new BuddyGroup(entry.getName(), ownerUid, serviceId); group.setName(entry.getName()); for (RosterEntry buddy: entry.getEntries()){ buddies.remove(buddy); group.getBuddyList().add(rosterEntry2Buddy(buddy, ownerUid, context, serviceId)); } return group; } @Override public List<BuddyGroup> rosterGroupCollection2BuddyGroupList(Collection<RosterGroup> entries, Collection<RosterEntry> buddies, String ownerUid, Context context, byte serviceId){ if (entries == null){ return null; } List<RosterEntry> list = new ArrayList<RosterEntry>(buddies); List<BuddyGroup> groups = new ArrayList<BuddyGroup>(entries.size()); for (RosterGroup entry: entries){ groups.add(rosterGroup2BuddyGroup(entry, list, ownerUid, context, serviceId)); } BuddyGroup noGroup = new BuddyGroup(ApiConstants.NO_GROUP_ID, ownerUid, serviceId); for (RosterEntry buddyWithNoGroup : list) { noGroup.getBuddyList().add(rosterEntry2Buddy(buddyWithNoGroup, ownerUid, context, serviceId)); } groups.add(noGroup); return groups; } @Override public Message textMessage2XMPPMessage(TextMessage textMessage, String thread, String to, Message.Type messageType) throws Exception { Message message = new Message(to, messageType); message.setThread(thread); message.setPacketID(textMessage.getMessageId() + ""); MessageEventManager.addNotificationsRequests(message, true, true, true, true); String buddyKey = null; if (edProvider != null && (buddyKey = edProvider.getKeyStorage().get(textMessage.getContactUid())) != null){ EncryptedMessage ems = new EncryptedMessage(); ems.setAndEncrypt(textMessage.getText(), buddyKey); //TODO message.setBody("Encrypted message"); message.addExtension(ems); } else { message.setBody(textMessage.getText()); } return message; } /** * @return the edProvider */ public EncryptedDataProvider getEdProvider() { return edProvider; } public void setEdProvider(EncryptedDataProvider edProvider) { this.edProvider = edProvider; } }